home *** CD-ROM | disk | FTP | other *** search
- /*
- * link.c -- linker main program that controls the linking process.
- */
-
- #include "../h/config.h"
- #include "general.h"
- #include "tproto.h"
- #include "globals.h"
- #include "link.h"
- #include "../h/paths.h"
- #include "../h/header.h"
-
- #ifdef Header
- #include "hdr.h"
-
- #ifndef MaxHeader
- #define MaxHeader MaxHdr
- #endif /* MaxHeader */
-
- #endif /* Header */
-
- /*
- * Prototype.
- */
-
- hidden novalue setexe Params((char *fname));
-
-
- /*
- * The following code is operating-system dependent [@link.01]. Include
- * system-dependent files and declarations.
- */
-
- #if PORT
- /* nothing to do */
- Deliberate Syntax Error
- #endif /* PORT */
-
- #if ARM
- #include "kernel.h"
- #include "swis.h"
- #endif /* ARM */
-
- #if AMIGA || ATARI_ST || HIGHC_386 || MACINTOSH || VM || VMS
- /* nothing to do */
- #endif /* AMIGA || ATARI_ST || HIGHC_386 ... */
-
- #if MSDOS
- #if MICROSOFT || TURBO
- #include <fcntl.h>
- #endif /* MICROSOFT || TURBO */
- #endif /* MSDOS */
-
- #if MVS
- char *routname; /* real output file name */
- #endif /* MVS */
-
- #if OS2
- #if MICROSOFT
- #include <fcntl.h>
- #endif /* MICROSOFT */
- #endif /* OS2 */
-
- #if UNIX
- #ifdef CRAY
- #define word word_fubar
- #include <sys/types.h>
- #include <sys/stat.h>
- #undef word
- #else /* CRAY */
- #include <sys/types.h>
- #include <sys/stat.h>
- #endif /* CRAY */
- #endif /* UNIX */
-
- /*
- * End of operating-system specific code.
- */
-
- FILE *infile; /* input file (.u1 or .u2) */
- FILE *outfile; /* interpreter code output file */
-
- #ifdef DeBugLinker
- FILE *dbgfile; /* debug file */
- static char dbgname[MaxFileName]; /* debug file name */
- #endif /* DeBugLinker */
-
- char inname[MaxFileName]; /* input file name */
- static char icnname[MaxFileName]; /* icon source file name */
-
- struct lfile *llfiles = NULL; /* List of files to link */
-
- #ifdef EvalTrace
- int colmno = 0; /* current source program colm number */
- #endif /* EvalTrace */
-
- int lineno = 0; /* current source program line number */
- int fatals = 0; /* number of errors encountered */
-
- /*
- * ilink - link a number of files, returning error count
- */
- int ilink(ifiles,outname)
- char **ifiles;
- char *outname;
- {
-
- int i;
- struct lfile *lf,*lfls;
- char *filename; /* name of current input file */
-
- linit(); /* initialize memory structures */
- while (*ifiles)
- alsolink(*ifiles++); /* make initial list of files */
-
- /*
- * Phase I: load global information contained in .u2 files into
- * data structures.
- *
- * The list of files to link is maintained as a queue with llfiles
- * as the base. lf moves along the list. Each file is processed
- * in turn by forming .u2 and .icn names from each file name, each
- * of which ends in .u1. The .u2 file is opened and globals is called
- * to process it. When the end of the list is reached, lf becomes
- * NULL and the loop is terminated, completing phase I. Note that
- * link instructions in the .u2 file cause files to be added to list
- * of files to link.
- */
- for (lf = llfiles; lf != NULL; lf = lf->lf_link) {
- filename = lf->lf_name;
- makename(inname, SourceDir, filename, U2Suffix);
- makename(icnname, TargetDir, filename, SourceSuffix);
-
- #if MVS || VM
- /*
- * Even though the ucode data is all reasonable text characters, use
- * of text I/O may cause problems if a line is larger than LRECL.
- * This is likely to be true with any compiler, though the precise
- * disaster which results may vary.
- */
- infile = fopen(inname, ReadBinary);
- #else
- infile = fopen(inname, ReadText);
- #endif /* MVS || VM */
-
- if (infile == NULL)
- quitf("cannot open %s",inname);
- readglob();
- fclose(infile);
- }
-
- /* Phase II: resolve undeclared variables and generate code. */
-
- /*
- * Open the output file.
- */
-
- #ifdef WATERLOO_C_V3_0
- strcat(outname," (BIN");
- #endif /* WATERLOO_C_V3_0 */
-
- #if MVS
- routname = outname;
- outfile = tmpfile(); /* write icode to temporary file to
- avoid fseek-PDS limitations */
- #else /* MVS */
- outfile = fopen(outname, WriteBinary);
- #endif /* MVS */
-
- /*
- * The following code is operating-system dependent [@link.02]. Set
- * untranslated mode if necessary.
- */
-
- #if PORT
- /* probably nothing */
- Deliberate Syntax Error
- #endif /* PORT */
-
- #if AMIGA || ARM || ATARI_ST || HIGHC_386 || MACINTOSH || MVS || UNIX || VM || VMS
- /* nothing to do */
- #endif /* AMIGA || ATARI_ST || ... */
-
- #if MSDOS
- #if LATTICE
- fmode(outfile,1); /* set for untranslated mode */
- #endif /* LATTICE */
- #if MICROSOFT || TURBO
- setmode(fileno(outfile),O_BINARY); /* set for untranslated mode */
- #endif /* MICROSOFT || TURBO */
- #endif /* MSDOS */
-
- #if OS2
- #if MICROSOFT
- setmode(fileno(outfile),O_BINARY);
- #endif /* MICROSOFT */
- #endif /* OS2 */
-
- /*
- * End of operating-system specific code.
- */
-
- if (outfile == NULL)
- quitf("cannot create %s",outname);
-
- #ifdef Header
- /*
- * Open Header, which contains the start-up program and copy it to the
- * output file. Then, write out null bytes to past the end of the
- * start-up program.
- */
- {
- int hsize;
- char hname[MaxFileName];
- char hdrdat[MaxHeader+1];
-
- #if MACINTOSH
- #if MPW
- { /* Look for header in same directory as the linker */
- char *p, *rindex();
-
- p = (char *)getenv("Command");
- if (p) {
- strcpy(hname,p);
- p = rindex(hname,':') + 1;
- }
- else
- p = hname;
- strcpy(p,HeaderPath);
- fprintf(stderr,HeaderPath);
- fflush(stderr);
- }
- #endif /* MPW */
- #endif /* MACINTOSH */
-
- fwrite(iconxhdr, sizeof(char), MaxHeader, outfile);
- }
- #endif /* Header */
-
- for (i = sizeof(struct header); i--;)
- putc(0, outfile);
- fflush(outfile);
- if (ferror(outfile) != 0)
- quit("unable to write to icode file");
-
- #ifdef DeBugLinker
- /*
- * Open the .ux file if debugging is on.
- */
- if (Dflag) {
- makename(dbgname, TargetDir, llfiles->lf_name, ".ux");
- dbgfile = fopen(dbgname, WriteText);
- if (dbgfile == NULL)
- quitf("cannot create %s", dbgname);
- }
- #endif /* DeBugLinker */
-
- /*
- * Loop through input files and generate code for each.
- */
- lfls = llfiles;
- while (lf = getlfile(&lfls)) {
- filename = lf->lf_name;
- makename(inname, SourceDir, filename, U1Suffix);
- makename(icnname, TargetDir, filename, SourceSuffix);
-
- #if MVS || VM
- infile = fopen(inname, ReadBinary);
- #else /* MVS || VM */
- infile = fopen(inname, ReadText);
- #endif /* MVS || VM */
-
- if (infile == NULL)
- quitf("cannot open %s", inname);
- gencode();
- fclose(infile);
- }
- gentables(); /* Generate record, field, global, global names,
- static, and identifier tables. */
- fclose(outfile);
- lmfree();
- if (fatals > 0)
- return fatals;
- setexe(outname);
- return 0;
- }
-
- /*
- * lwarn - issue a linker warning message.
- */
- novalue lwarn(s1, s2, s3)
- char *s1, *s2, *s3;
- {
- fprintf(stderr, "%s: ", icnname);
- if (lineno)
- fprintf(stderr, "Line %d # :", lineno);
- fprintf(stderr, "\"%s\": %s%s\n", s1, s2, s3);
- fflush(stderr);
- }
-
- /*
- * lfatal - issue a fatal linker error message.
- */
-
- novalue lfatal(s1, s2)
- char *s1, *s2;
- {
-
- fprintf(stderr, "%s: ", icnname);
- if (lineno)
- fprintf(stderr, "Line %d # : ", lineno);
- fprintf(stderr, "\"%s\": %s\n", s1, s2);
- fatals++;
- }
-
- /*
- * setexe - mark the output file as executable
- */
-
- static novalue setexe(fname)
- char *fname;
- {
-
- /*
- * The following code is operating-system dependent [@link.03]. It changes the
- * mode of executable file so that it can be executed directly.
- */
-
- #if PORT
- /* something is needed */
- Deliberate Syntax Error
- #endif /* PORT */
-
- #if AMIGA
- /* not necessary */
- #endif /* AMIGA */
-
- #if ARM
- {
- _kernel_swi_regs regs;
-
- regs.r[0] = 31;
- regs.r[1] = (int)"Icon";
- if (_kernel_swi(OS_FSControl,®s,®s) == NULL)
- {
- regs.r[0] = 18;
- regs.r[1] = (int)fname;
- _kernel_swi(OS_File,®s,®s);
- }
- }
- #endif /* ARM */
-
- #if ATARI_ST || MSDOS || MVS || OS2 || VM || VMS
- /* can't be made executable */
- /* note: VMS files can't be made executable, but see "iexe.com" under VMS. */
- #endif /* ATARI_ST || MSDOS || VMS */
-
- #if HIGHC_386
- /* not implemented yet. */
- #endif /* HIGHC_386 */
-
- #if MACINTOSH
- #if MPW
- /* Nothing to do here -- file is set to type TEXT
- (so it can be executed as a script) in tmain.c.
- */
- /* #pragma unused(fname) */
- #endif /* MPW */
- #endif /* MACINTOSH */
-
- #if MSDOS
- #if LATTICE || MICROSOFT || TURBO
- chmod(fname,0755); /* probably could be smarter... */
- #endif /* LATTICE || MICROSOFT || TURBO */
- #if MWC
- /* can't handle */
- #endif /* MWC */
- #endif /* MSDOS */
-
- #if UNIX
- {
- struct stat stbuf;
- int u, r, m;
- /*
- * Set each of the three execute bits (owner,group,other) if allowed by
- * the current umask and if the corresponding read bit is set; do not
- * clear any bits already set.
- */
- umask(u = umask(0)); /* get and restore umask */
- if (stat(fname,&stbuf) == 0) { /* must first read existing mode */
- r = (stbuf.st_mode & 0444) >> 2; /* get & position read bits */
- m = stbuf.st_mode | (r & ~u); /* set execute bits */
- chmod(fname,m); /* change file mode */
- }
- }
- #endif /* UNIX */
-
- /*
- * End of operating-system specific code.
- */
- }
-